package com.boot.admin.modules.sys.ai.service;

import cn.hutool.core.util.IdUtil;
import com.boot.admin.base.R;
import com.boot.admin.modules.sys.ai.model.entity.AiRole;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * AI文字转语音服务（TTS）- 委托给讯飞TTS实现
 *
 * @author 李飞洋
 * @date 2025/9/24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiTtsService {

    private final XfyunTtsStreamService xfyunTtsStreamService;

    @Value("${server.port:8088}")
    private String serverPort;

    @Value("${qiniu.tts.audio.base-path:audio}")
    private String audioBasePath;

    /**
     * 文字转语音（使用角色信息）
     */
    public R<String> generateAudio(String text, AiRole role) {
        try {
            if (text == null || text.trim().isEmpty()) {
                return R.NG("文本内容为空");
            }

            if (role == null) {
                return R.NG("角色信息为空");
            }

            log.info("开始调用讯飞TTS，文本长度: {}, 角色: {}", text.length(), role.getRoleName());

            // 使用同步方式调用TTS服务
            TtsSyncResult result = new TtsSyncResult();

            xfyunTtsStreamService.generateAudioBatch(text, role, new RealtimeVoiceService.TtsStreamCallback() {
                @Override
                public void onAudioChunk(byte[] audioData) {
                    result.appendAudioData(audioData);
                }

                @Override
                public void onComplete() {
                    result.setCompleted(true);
                    synchronized (result) {
                        result.notify();
                    }
                }

                @Override
                public void onError(String error) {
                    result.setError(error);
                    result.setCompleted(true);
                    synchronized (result) {
                        result.notify();
                    }
                }
            });

            // 等待完成
            synchronized (result) {
                try {
                    result.wait(30000); // 30秒超时
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return R.NG("TTS转换被中断");
                }
            }

            if (!result.isCompleted()) {
                return R.NG("TTS转换超时");
            }

            if (result.getError() != null) {
                return R.NG("TTS转换失败：" + result.getError());
            }

            byte[] audioData = result.getAudioData();
            if (audioData == null || audioData.length == 0) {
                return R.NG("未生成有效音频数据");
            }

            // 保存音频文件并返回URL
            String audioUrl = saveAudioFile(audioData, role);

            log.info("讯飞TTS生成完成，音频URL: {}", audioUrl);
            return R.OK(audioUrl);

        } catch (Exception e) {
            log.error("TTS转换失败", e);
            return R.NG("TTS转换失败: " + e.getMessage());
        }
    }

    /**
     * 文字转语音（兼容旧版本，仅使用voiceId）
     */
    public R<String> generateAudio(String text, String voiceId) {
        try {
            if (text == null || text.trim().isEmpty()) {
                return R.NG("文本内容为空");
            }

            log.info("开始调用讯飞TTS，文本长度: {}, 语音ID: {}", text.length(), voiceId);

            // 创建临时角色对象
            AiRole tempRole = new AiRole();
            tempRole.setVoiceId(voiceId);
            tempRole.setSpeakingRate(1.0);

            return generateAudio(text, tempRole);

        } catch (Exception e) {
            log.error("TTS转换失败", e);
            return R.NG("TTS转换失败: " + e.getMessage());
        }
    }

    /**
     * 生成音频chunk - 用于流式处理
     */
    public R<byte[]> generateAudioChunk(String textChunk, AiRole role) {
        try {
            if (textChunk == null || textChunk.trim().isEmpty()) {
                return R.NG("文本chunk为空");
            }

            if (role == null) {
                return R.NG("角色信息为空");
            }

            // 对于过短的文本chunk，可能不适合TTS处理
            if (textChunk.trim().length() < 2) {
                log.debug("文本chunk过短，跳过TTS处理: {}", textChunk);
                return R.OK(new byte[0]);
            }

            log.debug("开始处理文本chunk TTS，长度: {}", textChunk.length());

            // 使用同步方式调用TTS服务
            TtsSyncResult result = new TtsSyncResult();

            xfyunTtsStreamService.generateQuickAudio(textChunk, role, new RealtimeVoiceService.TtsStreamCallback() {
                @Override
                public void onAudioChunk(byte[] audioData) {
                    result.appendAudioData(audioData);
                }

                @Override
                public void onComplete() {
                    result.setCompleted(true);
                    synchronized (result) {
                        result.notify();
                    }
                }

                @Override
                public void onError(String error) {
                    result.setError(error);
                    result.setCompleted(true);
                    synchronized (result) {
                        result.notify();
                    }
                }
            });

            // 等待完成
            synchronized (result) {
                try {
                    result.wait(15000); // 15秒超时（chunk处理应该更快）
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return R.NG("TTS chunk转换被中断");
                }
            }

            if (!result.isCompleted()) {
                return R.NG("TTS chunk转换超时");
            }

            if (result.getError() != null) {
                return R.NG("TTS chunk转换失败：" + result.getError());
            }

            byte[] audioData = result.getAudioData();
            log.debug("TTS chunk生成完成，音频大小: {} bytes", audioData != null ? audioData.length : 0);
            return R.OK(audioData != null ? audioData : new byte[0]);

        } catch (Exception e) {
            log.error("TTS chunk转换失败", e);
            return R.NG("TTS chunk转换失败: " + e.getMessage());
        }
    }

    /**
     * 保存音频文件到resources目录
     */
    private String saveAudioFile(byte[] audioData, AiRole role) throws Exception {
        // 生成唯一的文件名
        String fileName = IdUtil.simpleUUID() + ".wav";

        // 构建保存路径（基于角色信息创建目录结构）
        StringBuilder pathBuilder = new StringBuilder();
        pathBuilder.append(audioBasePath).append("/");

        if (role.getLanguageCode() != null) {
            pathBuilder.append(role.getLanguageCode().toLowerCase()).append("/");
        } else {
            pathBuilder.append("default/");
        }

        if (role.getVoiceId() != null) {
            pathBuilder.append(role.getVoiceId()).append("/");
        }

        pathBuilder.append(fileName);

        // 获取resources目录的绝对路径
        String resourcePath = getResourcePath();

        // 完整的文件路径
        Path fullPath = Paths.get(resourcePath, pathBuilder.toString());

        // 确保目录存在
        Files.createDirectories(fullPath.getParent());

        // 写入文件
        Files.write(fullPath, audioData);

        // 构建访问URL
        String accessUrl = "http://localhost:" + serverPort + "/" + pathBuilder.toString().replace("\\", "/");

        log.info("音频文件保存成功: {}", fullPath.toString());
        log.debug("访问URL: {}", accessUrl);

        return accessUrl;
    }

    /**
     * 获取resources目录路径
     */
    private String getResourcePath() throws Exception {
        try {
            // 在开发环境中，获取src/main/resources路径
            ClassPathResource resource = new ClassPathResource("");
            File resourceDir = resource.getFile().getParentFile();
            return new File(resourceDir, "classes").getAbsolutePath();
        } catch (Exception e) {
            // 如果是打包后的环境，使用当前工作目录下的resources
            String resourcePath = System.getProperty("user.dir") + "/src/main/resources";

            // 如果resources不存在，创建并使用它
            File resourceDir = new File(resourcePath);
            if (!resourceDir.exists()) {
                resourceDir = new File(System.getProperty("user.dir") + "/resources");
                if (!resourceDir.exists()) {
                    resourceDir.mkdirs();
                }
                resourcePath = resourceDir.getAbsolutePath();
            }
            return resourcePath;
        }
    }

    /**
     * 估算语音时长（基于文字长度和语速）
     */
    public Integer estimateAudioDuration(String text, AiRole role) {
        if (text == null || text.trim().isEmpty()) {
            return 0;
        }

        int textLength = text.length();

        // 基础估算：中文平均每分钟300字，每秒5字
        double baseDuration = (double) textLength / 5.0;

        // 根据语速调整时长
        if (role != null && role.getSpeakingRate() != null && role.getSpeakingRate() > 0) {
            baseDuration = baseDuration / role.getSpeakingRate();
        }

        return Math.max(1, (int) Math.round(baseDuration)); // 最少1秒
    }

    /**
     * 估算语音时长（简单版本）
     */
    public Integer estimateAudioDuration(String text) {
        if (text == null || text.trim().isEmpty()) {
            return 0;
        }

        // 简单估算：中文平均每分钟300字，每秒5字
        int textLength = text.length();
        return Math.max(1, textLength / 5); // 最少1秒
    }

    /**
     * TTS同步结果辅助类
     */
    private static class TtsSyncResult {
        private byte[] audioData;
        private String error;
        private boolean completed = false;

        public synchronized void appendAudioData(byte[] data) {
            if (audioData == null) {
                audioData = data.clone();
            } else {
                byte[] newData = new byte[audioData.length + data.length];
                System.arraycopy(audioData, 0, newData, 0, audioData.length);
                System.arraycopy(data, 0, newData, audioData.length, data.length);
                audioData = newData;
            }
        }

        public byte[] getAudioData() { return audioData; }
        public String getError() { return error; }
        public void setError(String error) { this.error = error; }
        public boolean isCompleted() { return completed; }
        public void setCompleted(boolean completed) { this.completed = completed; }
    }
}